﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace CSMA_CA
{
    public partial class F_MAIN : Form
    {
		C_NODE	ND = new C_NODE();

        int		TRMN; // Terminals
        int		TRNS; // Transmission Rate
        int		DSTC; // Distance between Two Neighbor Terminals
		int		SZPK; // The Size of Packet
		int		DCNT;

		int		POST; // Postion 
		int		MOVE; // Movie ID
		int		TRGT; // Target ID

		bool	ONCE; // Only One Excution
		bool	BUSY; // busy: true, IDLE: false

		Random R = new Random((int)DateTime.Now.Millisecond % 999);
		//Random R = new Random( C_COMM.SEED );

		Stopwatch WTCH = new Stopwatch();


		C_NODE[] TM;
		Button[] BT;
		Button[] DT;

		public F_MAIN()
        {
            InitializeComponent();

			// Set Double-Buffering
			SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.DoubleBuffer, true);

			TB_TRNS.Focus();
        }

		/******************************************************************************************
		 * Component Events
		 * ***************************************************************************************/

		private void BT_MAKE_Click(object sender, EventArgs e)
		{
			SetTextBox();
			
			TM = new C_NODE[TRMN];
			BT = new Button[TRMN];
			DT = new Button[1000];

			CreateTerminals();
			ConnectTerimalsToMainLine();
		}

		void BT_NODE_Click(object sender, EventArgs e)
		{
			int i = int.Parse(((Button)sender).Name);
			TRGT = i;
			ONCE = true;
			DCNT = 0;

			SetDataGrid();
			MakeDataButton(i);
			TM_TRNS.Start();

			PlusColumn( TRGT, 0 );
			ChangeBTColor( C_COMM.CTRN, TRGT );
		}

		private void BT_PLAY_Click(object sender, EventArgs e)
		{
			ONCE = false;
			DCNT = 0;

			SetDataGrid();
			MakeDataButton(TRGT);
			TM_TRNS.Start();
			WTCH.Start();

			PlusColumn( TRGT, 0 );
			ChangeBTColor( C_COMM.CTRN, TRGT );
		}

		private void BT_STOP_Click(object sender, EventArgs e)
		{
			TM_TRNS.Stop();
		}

		private void TM_TRNS_Tick(object sender, EventArgs e)
		{
			if ( DT[DCNT].Top >= C_COMM.LINE )
			{
				DT[DCNT].Top = DT[DCNT].Top - 10;
				ConnectTerimalsToMainLine();
			}
			else
			{
				if ( MakeCollision() == true )
				{
					if ( CK_BACK.Checked == false )
					{
						MakeDataButtonMore();
						SetCollision();

						ClearDataButton();
						ConnectTerimalsToMainLine();
					}
					System.Threading.Thread.Sleep( 1000 );
				}
				else
				{
					TM_TRNS.Stop();

					POST = ChoiceTerminalPostion();
					ChangeBTColor( C_COMM.CRCV, MOVE );

					SetBusy();

					if ( TRGT < MOVE )
						TM_MOVR.Start();
					else
						TM_MOVL.Start();
				}
			}
		}

		private void TM_MOVL_Tick(object sender, EventArgs e)
		{
			if ( DT[DCNT].Left - 8 > POST )
			{
				DT[DCNT].Left = DT[DCNT].Left - 10;
				ConnectTerimalsToMainLine();
			}
			else 
			{
				TM_MOVL.Stop();
				TM_RECV.Start();
			}
		}

		private void TM_MOVR_Tick(object sender, EventArgs e)
		{
			if (DT[DCNT].Left < POST )
			{
				DT[DCNT].Left = DT[DCNT].Left + 10;
				ConnectTerimalsToMainLine();
			}
			else
			{
				TM_MOVR.Stop();
				TM_RECV.Start();
			}
		}

		private void TM_RECV_Tick(object sender, EventArgs e)
		{
			if (DT[DCNT].Top <= C_COMM.BTTN)
			{
				DT[DCNT].Top = DT[DCNT].Top + 10;
				ConnectTerimalsToMainLine();
			}
			else
			{
				SetIdle();
				PlusColumn( TRGT, 1 );
				PlusColumn( MOVE, 2 );

				ChangeBTColor( C_COMM.CNRM, TRGT );
				ChangeBTColor( C_COMM.CNRM, MOVE );

				if ( ONCE == true )
					TM_RECV.Stop();

				else
				{
					if ( DCNT <= C_COMM.REPT )
						MakeDataButtonMore();
					else
						SetTime();

					TM_RECV.Stop();
				}
			}
		}	

		/******************************************************************************************
		 * Functions
		 * ***************************************************************************************/

		void SetTextBox()
		{
			TRMN = int.Parse( TB_TRMN.Text );
			TRNS = int.Parse( TB_TRNS.Text );
			DSTC = int.Parse( TB_DSTC.Text );
			SZPK = int.Parse( TB_SZPK.Text );
		}

		void SetDataGrid()
		{
			DG_RSLT.Rows.Add( 3 );

			DG_RSLT.Rows[ 0 ].HeaderCell.Value = C_COMM.RWH0;
			DG_RSLT.Rows[ 1 ].HeaderCell.Value = C_COMM.RWH1;
			DG_RSLT.Rows[ 2 ].HeaderCell.Value = C_COMM.RWH2;

			for ( int i = 0; i < DG_RSLT.ColumnCount; i++ )
			{
				for ( int j = 0; j < DG_RSLT.RowCount; j++ )
					DG_RSLT[ i, j ].Value = 0;
			}
		}

		void CreateTerminals()
		{
			for ( int i = 0; i < TRMN; i++ )
			{
				TM[i] = new C_NODE();

				BT[i] = new Button();
				BT[i].Name = i.ToString();

				BT[i].Width = 30;
				BT[i].Height = 30;

				BT[i].Left = 30 + (i * 100);
				BT[i].Top = 150;

				TM[i].NDID = i;
				TM[i].POSX = BT[i].Left;
				TM[i].POSY = BT[i].Top;

				PN_GRP2.Controls.Add(BT[i]);

				BT[i].Click += new System.EventHandler(BT_NODE_Click);
			}
		}

		void ConnectTerimalsToMainLine()
		{
			for( int i = 0; i < TRMN; i++ )
			{
				Pen P = new Pen( Color.DimGray, 5 );
				P.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
				Graphics G = ( ( Panel ) PN_GRP2 ).CreateGraphics();

				G.DrawLine( P, BT[i].Left+15, BT[i].Top, 45+( i * 100), 50);
			}
		}

		void MakeDataButton(int i)
		{
			 DT[DCNT] = new Button();

			 DT[DCNT].Name = DCNT.ToString();

			 DT[DCNT].Left = TM[i].POSX + 8;
			 DT[DCNT].Top = TM[i].POSY - 10;

			 DT[DCNT].Width = 16;
			 DT[DCNT].Height = 16;

			 DT[DCNT].BackColor = Color.Red;

			 PN_GRP2.Controls.Add(DT[DCNT]);
		}

		void MakeDataButtonMore()
		{
			DCNT++;

			TRGT = ChoiceTerminal();
			MakeDataButton( TRGT );
			TM_TRNS.Start();

			PlusColumn( TRGT, 0 );
			ChangeBTColor( C_COMM.CTRN, TRGT );
		}

		void ClearDataButton()
		{
			DT[--DCNT].Visible = false;
			DCNT++;
			DT[ DCNT ].Visible = true;

			for ( int i = 0; i < int.Parse( TB_TRMN.Text.ToString() ); i++ )
				ChangeBTColor( C_COMM.CNRM, i );
		}
		
		int ChoiceTerminal()
		{
			int mnum = int.Parse(TB_TRMN.Text);
			int rand = -1;

			while (true)
			{
				rand = R.Next(0, mnum);

				if (rand != TRGT)
					break;
			}

			return rand;
		}
		
		int ChoiceTerminalPostion()
		{
			int rand = ChoiceTerminal();

			switch ( rand )
			{
				case 0:
					MOVE = 0;
					return C_COMM.TM00;
				case 1:
					MOVE = 1;
					return C_COMM.TM01;
				case 2:
					MOVE = 2;
					return C_COMM.TM02;
				case 3:
					MOVE = 3;
					return C_COMM.TM03;
				case 4:
					MOVE = 4;
					return C_COMM.TM04;
				case 5:
					MOVE = 5;
					return C_COMM.TM05;
				case 6:
					MOVE = 6;
					return C_COMM.TM06;
				case 7:
					MOVE = 7;
					return C_COMM.TM07;
				case 8:
					MOVE = 8;
					return C_COMM.TM08;
				case 9:
					MOVE = 9;
					return C_COMM.TM09;
				default:
					return -9;
			}
		}
		
		void PlusColumn( int c, int r )
		{
			int numb = int.Parse( DG_RSLT[ c, r].Value.ToString() );
			DG_RSLT[ c, r ].Value = ++numb;
		}	

		void ChangeBTColor( int c, int i )
		{
			switch ( c )
			{
				case C_COMM.CNRM:
					BT[i].BackColor = SystemColors.Control;
					break;
				case C_COMM.CTRN:
					BT[i].BackColor = Color.Blue;
					break;
				case C_COMM.CRCV:
					BT[ i ].BackColor = Color.Yellow;
					break;
			}
		}

		void SetIdle()
		{
			BUSY = false;
			TB_BUSY.Text = C_COMM.IDLE;
		}

		void SetBusy()
		{
			BUSY = true;
			TB_BUSY.Text = C_COMM.BUSY;
		}

		void SetCollision()
		{
			BUSY = true;
			TB_BUSY.Text = C_COMM.COLL;
		}

		void SetTime()
		{
			WTCH.Stop();
			TB_TIME.Text = WTCH.Elapsed.Minutes.ToString() + ":" + WTCH.Elapsed.Seconds.ToString() + ":" + WTCH.Elapsed.Milliseconds.ToString();
		}

		bool MakeCollision()
		{
			int prob = int.Parse( TB_PROB.Text.ToString() );
			int rand = R.Next( 0, 99 );

			if ( rand < prob )
				return true;

			return false;
		}
	}		 
}
